package whut.pso;

import org.apache.commons.math3.util.FastMath;
import whut.commons.IProblemSet;
import whut.commons.Location;

import java.util.Random;

/**
 * Created by Justin on 2018-04-04
 */
public class RSPSOSwarm implements IUpdateSwarm{
    private final int RS = 100;
    private final double W_LOWERBOUND = 0.3;
    private final double W_UPPERBOUND = 0.6;
    @Override
    public double[] updateSwarm(double[] currLoc, double[] pBest, double[] gBest, double w, INormalization normalize,
                            IProblemSet problem) {
        Random generator = new Random();
        int PROBLEM_DIMENSION = pBest.length;
        double alpha = W_LOWERBOUND + generator.nextDouble() * (W_UPPERBOUND - W_LOWERBOUND);
        double[] currP = currLoc;
        double prevValue = problem.evaluate(new Location(currLoc));

        for (int j = 0; j < PROBLEM_DIMENSION; j++) {
            int flag = 0;
            double attractor = alpha * pBest[j] + (1 - alpha) * gBest[j];  //维度上的吸引子
            double diff = currP[j] - attractor;
            double shock = Math.abs(diff);   //每维震荡因子
            double[] value = new double[RS];   //存放震荡后适应度值
            double[] newloc = new double[RS];  //存放震荡后维度上的值

//            System.out.println("shock = " + shock);
            if (shock == 0) continue;

            for (int k = 0; k < RS; k++) {
                if (diff > 0) flag = -1;
                else flag = 1;
                double shockRange = 2 * shock - 2 * shock * k / RS;
                newloc[k] = currP[j] + flag * shockRange;

                currP[j] = newloc[k];
                if (normalize != null) {
                    currP = normalize.normalizeLocationOfRange(currP, null, 0);
                    newloc[k] =  currP[j];
                }
                Location loc = new Location(currP);
                value[k] = problem.evaluate(loc);
            }

            int index = PSOUtility.getMinPos(value);
//            if (FastMath.abs(value[index] - prevValue) < 1e-9){
                currP[j] = newloc[index];           //每次都在当前的最优下，到下一维度去震荡
//                prevValue = value[index];
//            }
        }

        return currP;
//        Location loc = new Location(currP);
//        p.setLocation(loc);
    }
}
